namespace OasisCiq.Xml
{
    using System.Xml;
    using Xnl;

    public class XnlXmlWriter
    {
        private const string XmlNS = XmlNamespaces.Name;
        private readonly CommonTypesXmlWriter ctWriter;
        private readonly XLinkXmlWriter xLinkWriter;
        private readonly XmlWriter writer;

        public XnlXmlWriter(XmlWriter writer)
        {
            this.writer = writer;
            ctWriter = new CommonTypesXmlWriter(writer);
            xLinkWriter = new XLinkXmlWriter(writer);
        }

        public void WriteNameLine(NameLine element)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement("NameLine", XmlNS);
            if (element.Type != null)
            {
                writer.WriteAttributeString("Type", XmlNS, element.Type.ToString());
            }

            ctWriter.WriteAbbreviationGroup(element);
            ctWriter.WriteDataQualityGroup(element);
            ctWriter.WriteExtendedAttributes(element);
            writer.WriteString(element.ToString());
            writer.WriteEndElement();
        }

        public void WritePersonName(PersonNameType element)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement("PersonName", XmlNS);
            if (element.Type != null)
            {
                writer.WriteAttributeString("Type", XmlNS, element.Type.ToString());
            }

            if (element.PersonId != null)
            {
                writer.WriteAttributeString("PersonID", XmlNS, element.PersonId.ToString());
            }

            if (element.PersonIdType != null)
            {
                writer.WriteAttributeString("PersonIDType", XmlNS, element.PersonIdType.ToString());
            }

            if (element.Id != null)
            {
                writer.WriteAttributeString("ID", XmlNS, element.Id.ToString());
            }

            if (element.Usage != null)
            {
                writer.WriteAttributeString("Usage", XmlNS, element.Usage.ToString());
            }
            
            ctWriter.WriteStatusList(element.Status, XmlNS);
            ctWriter.WriteValidityDateGroup(element);
            WriteNameKeyGroup(element.NameKey);
            xLinkWriter.WriteXLink(element);
            ctWriter.WriteDataQualityGroup(element);
            ctWriter.WriteLanguageCodeGroup(element);
            ctWriter.WriteExtendedAttributes(element);
           
            if (element.NameElements != null)
            {
                foreach (var personNameElement in element.NameElements)
                {
                    WritePersonNameElement(personNameElement);
                }
            }

            writer.WriteEndElement();
        }

        public void WriteOrganisationName(OrganisationNameType element)
        {
            WriteOrganisationName(element, "OrganisationName", XmlNS);
        }

        public void WriteOrganisationName(
            OrganisationNameType element,
            string elementName,
            string @namespace)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement(elementName, @namespace);
            if (element.Type != null)
            {
                writer.WriteAttributeString("Type", XmlNS, element.Type.ToString());
            }

            if (element.OrganisationId != null)
            {
                writer.WriteAttributeString("OrganisationID", XmlNS, element.OrganisationId.ToString());
            }

            if (element.OrganisationIdType != null)
            {
                writer.WriteAttributeString("OrganisationIDType", XmlNS, element.OrganisationIdType.ToString());
            }

            if (element.Id != null)
            {
                writer.WriteAttributeString("ID", XmlNS, element.Id.ToString());
            }

            if (element.Usage != null)
            {
                writer.WriteAttributeString("Usage", XmlNS, element.Usage.ToString());
            }

            ctWriter.WriteStatusList(element.Status, XmlNS);
            ctWriter.WriteValidityDateGroup(element);
            WriteNameKeyGroup(element.NameKey);
            xLinkWriter.WriteXLink(element);
            ctWriter.WriteDataQualityGroup(element);
            ctWriter.WriteLanguageCodeGroup(element);
            ctWriter.WriteExtendedAttributes(element);

            if (element.NameElements != null)
            {
                foreach (var organizationNameElement in element.NameElements)
                {
                    WriteOrganisationNameElement(organizationNameElement);
                }
            }

            if (element.SubDivisions != null)
            {
                foreach (var subDivision in element.SubDivisions)
                {
                    WriteSubDivisionName(subDivision);
                }
            }

            writer.WriteEndElement();
        }

        public void WritePartyName(PartyNameType element)
        {
            WritePartyName(element, "PartyName", XmlNS);
        }

        public void WritePartyName(PartyNameType element, string elementName, string elementNamespace)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement(elementName, elementNamespace);
            WritePartyNameAttributes(element);
            WritePartyNameChildren(element);
            writer.WriteEndElement();
        }

        public void WritePartyNameAttributes(PartyNameType element)
        {
            if (element == null)
            {
                return;
            }

            if (element.PartyNameId != null)
            {
                writer.WriteAttributeString("PartyNameID", XmlNS, element.PartyNameId.ToString());
            }

            if (element.PartyNameIdType != null)
            {
                writer.WriteAttributeString("PartyNameIDType", XmlNS, element.PartyNameIdType.ToString());
            }

            if (element.Id != null)
            {
                writer.WriteAttributeString("ID", XmlNS, element.Id.ToString());
            }

            if (element.Usage != null)
            {
                writer.WriteAttributeString("Usage", XmlNS, element.Usage.ToString());
            }

            ctWriter.WriteStatusList(element.Status, XmlNS);
            if (element.JointNameConnector != null)
            {
                writer.WriteAttributeString("JointNameConnector", XmlNS, element.JointNameConnector.ToString());
            }

            ctWriter.WriteValidityDateGroup(element);
            WriteNameKeyGroup(element.NameKey);
            xLinkWriter.WriteXLink(element);
            ctWriter.WriteDataQualityGroup(element);
            ctWriter.WriteLanguageCodeGroup(element);
            ctWriter.WriteExtendedAttributes(element);
        }

        public void WritePartyNameChildren(PartyNameType element)
        {
            if (element == null)
            {
                return;
            }

            if (element.NameLines != null)
            {
                foreach (var nameLine in element.NameLines)
                {
                    WriteNameLine(nameLine);
                }
            }

            if (element.PersonNames != null)
            {
                foreach (var personName in element.PersonNames)
                {
                    WritePersonName(personName);
                }
            }

            if (element.OrganisationNames != null)
            {
                foreach (var organisationName in element.OrganisationNames)
                {
                    WriteOrganisationName(organisationName);
                }
            }
        }

        public void WritePersonNameElement(PersonNameElement element)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement("NameElement", XmlNS);
            if (element.ElementType != null)
            {
                writer.WriteAttributeString("ElementType", XmlNS, element.ElementType.ToString());
            }
            
            ctWriter.WriteAbbreviationGroup(element);
            ctWriter.WriteExtendedAttributes(element);
            writer.WriteString(element.ToString());
            writer.WriteEndElement();
        }

        public void WriteOrganisationNameElement(OrganisationNameElement element)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement("NameElement", XmlNS);
            if (element.ElementType != null)
            {
                writer.WriteAttributeString("ElementType", XmlNS, element.ElementType.ToString());
            }

            ctWriter.WriteAbbreviationGroup(element);
            ctWriter.WriteExtendedAttributes(element);
            writer.WriteString(element.ToString());
            writer.WriteEndElement();
        }

        public void WriteSubDivisionName(SubDivisionName element)
        {
            if (element == null)
            {
                return;
            }

            writer.WriteStartElement("SubDivisionName", XmlNS);
            if (element.Type != null)
            {
                writer.WriteAttributeString("Type", XmlNS, element.Type.ToString());
            }

            ctWriter.WriteAbbreviationGroup(element);
            ctWriter.WriteExtendedAttributes(element);
            writer.WriteString(element.ToString());
            writer.WriteEndElement();
        }

        public void WriteNameKeyGroup(NameKeyGroup group)
        {
            if (group == null)
            {
                return;
            }

            if (group.NameKey != null)
            {
                writer.WriteAttributeString("NameKey", XmlNS, group.NameKey.ToString());
            }

            if (group.NameKeyRef != null)
            {
                writer.WriteAttributeString("NameKeyRef", XmlNS, group.NameKeyRef.ToString());
            }
        }
    }
}